Martian Gothic: Unification 3.0 fixing tutorial.
by EOD //[UCF]

I thought to call it winxp fix. But as you will see the error is not windows xp related.

For thouse who want to know what was done for the game to work.
Addresses are from 3.0 version.

Error occures here:

.text:00424975                 mov     eax, dword_5BD030	//0x500
.text:0042497A                 mov     edi, dword_5BD02C	//destination
.text:00424980                 and     eax, 0FFFFh
.text:00424985                 lea     ecx, [eax+eax*4]	//*5
.text:00424988                 xor     eax, eax		//fill with 0
.text:0042498A                 shl     ecx, 7		//*128
.text:0042498D                 mov     edx, ecx
.text:0042498F                 shr     ecx, 2		//divide by 4 (how many dwords)
.text:00424992                 rep stosd		//zero buffer
.text:00424994                 mov     ecx, edx
.text:00424996                 and     ecx, 3
.text:00424999                 rep stosb

Here we have buffer zeroed.
And we zero 500h*5*128 = 0xC8000

A little later we see the same operation:

.text:004249C8                 mov     eax, dword_5BD030
.text:004249CD                 mov     edi, dword_5BD02C
.text:004249D3                 and     eax, 0FFFFh
.text:004249D8                 lea     ecx, [eax+eax*4]
.text:004249DB                 xor     eax, eax
.text:004249DD                 shl     ecx, 7
.text:004249E0                 mov     edx, ecx
.text:004249E2                 shr     ecx, 2
.text:004249E5                 rep stosd
.text:004249E7                 mov     ecx, edx
.text:004249E9                 and     ecx, 3
.text:004249EC                 rep stosb

Buffer address are at dword_5BD02C.
If we will nop "rep stosd" command in these 2 places the game will run ok.
So the error is in buffer size or in size of zeroing.
Lets find out why it occurs.

This variable (buffer pointer) is initialized here:

.text:00427591                 mov     edx, [esp+28h]
.text:00427595                 mov     ax, [esp+14h]
.text:0042759A                 mov     dword_5BD02C, edx

It is returned to [esp+28] by ddraw function that is called here:

.text:0042743A                 mov     eax, dword_74C0B4
.text:0042743F                 push    0
.text:00427441                 lea     edx, [esp+84h+var_7C]
.text:00427445                 push    1
.text:00427447                 mov     ecx, [eax]
.text:00427449                 push    edx
.text:0042744A                 push    0
.text:0042744C                 push    eax
.text:0042744D                 call    dword ptr [ecx+64h]    //here

This function is:
DD_Surface_Lock(x, x, x, x, x)
(name got using IDA Pro, PDB file from Microsoft server, and 0x7377628B address of called function)
Because our buffer address is in the stack, it must be part of some structure that is filled by this ddraw function.
I found the structure that looks like the one - DDSURFACEDESC.
And it has these members:

typedef struct _DDSURFACEDESC {
  DWORD dwSize;
  DWORD dwFlags;
  DWORD dwHeight;
  DWORD dwWidth;
  LONG lPitch;				//// 500h = 1280
  LONG lXPitch;
  DWORD dwBackBufferCount;
  DWORD dwRefreshRate;
  LPVOID lpSurface;				//this is our buffer
  DDCOLORKEY ddckCKDestOverlay;
  DDCOLORKEY ddckCKDestBlt;
  DDCOLORKEY ddckCKSrcOverlay;
  DDCOLORKEY ddckCKSrcBlt;
  DDPIXELFORMAT ddpfPixelFormat;
  DDSCAPS ddsCaps;
  DWORD dwSurfaceSize;
} DDSURFACEDESC, FAR* LPDDSURFACEDESC; 

As you can see we have our buffer size calculated this way:
500h*5*128
Its the same as 1280*640.
That is how many bytes it tries to zero.
1280 is our width of surface * 2 (16 bits per pixel).
So our width will be 640.
But then the question arise: why our height is 640 (128*5) too ?
This must be the error in the code because game runs in resolution 640x480.
Lets fix it.
We already have multiply by 5.
So we need to multiply 480/5 = 96 - instead of 128.
Thats why we change shl 7 (*128) by imul ecx,60h (*96)

In short the error was in incorrect height, that was set to 640 instead of 480, and thats why
program tried to zero more bytes then was allocated (640*640*2 instead of 640*480*2).
And this error caused memory access violation.

Enjoy!